﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using ConsoleApplication1;

namespace PQ.Util
{
    public class PQAlgo
    {
        public static int DELTA = 1;
        public static int STAR = 2;
        AccessUtil accessUtil;
        //用于保存12通道未处理的原始数据，
        double[][] data;

        Configuration cfg;

        int wiringType;
        //用于保存各具体通道下标
        int indexUA , indexUB , indexUC, indexUN, indexUZ, indexIA, indexIB, indexIC, indexIN;

        Double IArms = 0.0, IBrms = 0.0, ICrms = 0.0, INrms = 0.0, UArms = 0.0, UBrms = 0.0, UCrms = 0.0, UNrms = 0.0, UZrms = 0.0, FA = 0.0, FB = 0.0, FC = 0.0,
            PA = 0.0, PB = 0.0, PC = 0.0, P = 0.0, QA = 0.0, QB = 0.0, QC = 0.0, Q = 0.0, PFA = 0.0, PFB = 0.0, PFC = 0.0, PF = 0.0, SA = 0.0, SB = 0.0, SC = 0.0, S = 0.0, PFAA = 0.0, PFAB = 0.0, PFAC = 0.0;
        double[] harmUA = new double[51];
        double[] harmUB = new double[51];
        double[] harmUC = new double[51];

        double[] harmIA = new double[51];
        double[] harmIB = new double[51];
        double[] harmIC = new double[51];

        double[][] data3s = new double[15][];
        double[][] data10min = new double[200][];

        int index3s = 0;
        int index10min = 0;
        bool readFlag = true;

        Random random = new Random();
        public PQAlgo(Configuration cfg,AccessUtil accessUtil)
        {
            this.cfg = cfg;
            this.accessUtil = accessUtil;

            indexUA = cfg.indexUA;
            indexUB = cfg.indexUB;
            indexUC = cfg.indexUC;
            indexUN = cfg.indexUN;
            indexUZ = cfg.indexUZ;

            indexIA = cfg.indexIA;
            indexIB = cfg.indexIB;
            indexIC = cfg.indexIC;
            indexIN = cfg.indexIN;
            for (int i = 0; i < 15; i++)
            {
                data3s[i] = new double[32];
            }
            for (int i = 0; i < 200; i++)
            {
                data10min[i] = new double[32];
            }
        }
        public void calc(double[][] data)
        {
            this.data = data;
            basicCalc();
            saveBasicValue("200ms");
            calcHarm();

            calc3s();
        }
        public void run()
        {
            while (readFlag)
            {
                if (cfg.dataExchange.Count != 0)
                {
                    DataValue dv = (DataValue)cfg.dataExchange[0];
                    dv.restoreValue();
                    calc(dv.data);
                    cfg.dataExchange.RemoveAt(0);
                }
                else
                {
                    Thread.Sleep(100);
                }
            }
        }
        public void stop()
        {
            readFlag = false;
        }
        private void calc3s()
        {
            data3s[index3s][0] = IArms;
            data3s[index3s][1] = IBrms;
            data3s[index3s][2] = ICrms;
            data3s[index3s][3] = INrms;

            data3s[index3s][4] = UArms;
            data3s[index3s][5] = UBrms;
            data3s[index3s][6] = UCrms;
            data3s[index3s][7] = UNrms;
            data3s[index3s][8] = UZrms;

            data3s[index3s][9] = FA;
            data3s[index3s][10] = FB;
            data3s[index3s][11] = FC;

            data3s[index3s][12] = PA;
            data3s[index3s][13] = PB;
            data3s[index3s][14] = PC;
            data3s[index3s][15] = P;

            data3s[index3s][16] = QA;
            data3s[index3s][17] = QB;
            data3s[index3s][18] = QC;
            data3s[index3s][19] = Q;

            data3s[index3s][20] = PFA;
            data3s[index3s][21] = PFB;
            data3s[index3s][22] = PFC;
            data3s[index3s][23] = PF;

            data3s[index3s][24] = SA;
            data3s[index3s][25] = SB;
            data3s[index3s][26] = SC;
            data3s[index3s][27] = S;

            data3s[index3s][28] = PFAA;
            data3s[index3s][29] = PFAB;
            data3s[index3s][30] = PFAC;
            data3s[index3s][31] = PFA;

            if (++index3s == 15)
            {
                index3s = 0;
                for (int i = 0; i < 32; i++)
                {
                    double temp = 0.0;
                    for (int j = 0; j < 15; j++)
                    {
                        temp += data3s[j][i] * data3s[j][i];
                    }
                    temp = Math.Sqrt(temp / 15);
                    switch(i)
                    {
                        case 0:
                            IArms = temp;
                            break;
                        case 1:
                            IBrms = temp;
                            break;
                        case 2:
                            ICrms = temp;
                            break;
                        case 3:
                            INrms = temp;
                            break;
                        case 4:
                            UArms = temp;
                            break;
                        case 5:
                            UBrms = temp;
                            break;
                        case 6:
                            UCrms = temp;
                            break;
                        case 7:
                            UNrms = temp;
                            break;
                        case 8:
                            UZrms = temp;
                            break;
                        case 9:
                            FA = temp;
                            break;
                        case 10:
                            FB = temp;
                            break;
                        case 11:
                            FC = temp;
                            break;
                        case 12:
                            PA = temp;
                            break;
                        case 13:
                            PB = temp;
                            break;
                        case 14:
                            PC = temp;
                            break;
                        case 15:
                            P = temp;
                            break;
                        case 16:
                            QA = temp;
                            break;
                        case 17:
                            QB = temp;
                            break;
                        case 18:
                            QC = temp;
                            break;
                        case 19:
                            Q = temp;
                            break;
                        case 20:
                            PFA = temp;
                            break;
                        case 21:
                            PFB = temp;
                            break;
                        case 22:
                            PFC = temp;
                            break;
                        case 23:
                            PF = temp;
                            break;
                        case 24:
                            SA = temp;
                            break;
                        case 25:
                            SB = temp;
                            break;
                        case 26:
                            SC = temp;
                            break;
                        case 27:
                            S = temp;
                            break;
                        case 28:
                            PFAA = temp;
                            break;
                        case 29:
                            PFAB = temp;
                            break;
                        case 30:
                            PFAC = temp;
                            break;
                        case 31:
                            PFA = temp;
                            break;
                    }//swith
                }//for
                saveBasicValue("3s");
                calc10min();
            }
        }
        private void calc10min()
        {
            data10min[index10min][0] = IArms;
            data10min[index10min][1] = IBrms;
            data10min[index10min][2] = ICrms;
            data10min[index10min][3] = INrms;

            data10min[index10min][4] = UArms;
            data10min[index10min][5] = UBrms;
            data10min[index10min][6] = UCrms;
            data10min[index10min][7] = UNrms;
            data10min[index10min][8] = UZrms;

            data10min[index10min][9] = FA;
            data10min[index10min][10] = FB;
            data10min[index10min][11] = FC;

            data10min[index10min][12] = PA;
            data10min[index10min][13] = PB;
            data10min[index10min][14] = PC;
            data10min[index10min][15] = P;

            data10min[index10min][16] = QA;
            data10min[index10min][17] = QB;
            data10min[index10min][18] = QC;
            data10min[index10min][19] = Q;

            data10min[index10min][20] = PFA;
            data10min[index10min][21] = PFB;
            data10min[index10min][22] = PFC;
            data10min[index10min][23] = PF;

            data10min[index10min][24] = SA;
            data10min[index10min][25] = SB;
            data10min[index10min][26] = SC;
            data10min[index10min][27] = S;

            data10min[index10min][28] = PFAA;
            data10min[index10min][29] = PFAB;
            data10min[index10min][30] = PFAC;
            data10min[index10min][31] = PFA;

            if (++index10min == 200)
            {
                index10min = 0;
                for (int i = 0; i < 32; i++)
                {
                    double temp = 0.0;
                    for (int j = 0; j < 200; j++)
                    {
                        temp += data10min[j][i] * data10min[j][i];
                    }
                    temp = Math.Sqrt(temp / 15);
                    switch (i)
                    {
                        case 0:
                            IArms = temp;
                            break;
                        case 1:
                            IBrms = temp;
                            break;
                        case 2:
                            ICrms = temp;
                            break;
                        case 3:
                            INrms = temp;
                            break;
                        case 4:
                            UArms = temp;
                            break;
                        case 5:
                            UBrms = temp;
                            break;
                        case 6:
                            UCrms = temp;
                            break;
                        case 7:
                            UNrms = temp;
                            break;
                        case 8:
                            UZrms = temp;
                            break;
                        case 9:
                            FA = temp;
                            break;
                        case 10:
                            FB = temp;
                            break;
                        case 11:
                            FC = temp;
                            break;
                        case 12:
                            PA = temp;
                            break;
                        case 13:
                            PB = temp;
                            break;
                        case 14:
                            PC = temp;
                            break;
                        case 15:
                            P = temp;
                            break;
                        case 16:
                            QA = temp;
                            break;
                        case 17:
                            QB = temp;
                            break;
                        case 18:
                            QC = temp;
                            break;
                        case 19:
                            Q = temp;
                            break;
                        case 20:
                            PFA = temp;
                            break;
                        case 21:
                            PFB = temp;
                            break;
                        case 22:
                            PFC = temp;
                            break;
                        case 23:
                            PF = temp;
                            break;
                        case 24:
                            SA = temp;
                            break;
                        case 25:
                            SB = temp;
                            break;
                        case 26:
                            SC = temp;
                            break;
                        case 27:
                            S = temp;
                            break;
                        case 28:
                            PFAA = temp;
                            break;
                        case 29:
                            PFAB = temp;
                            break;
                        case 30:
                            PFAC = temp;
                            break;
                        case 31:
                            PFA = temp;
                            break;
                    }//swith
                }//for
                saveBasicValue("10min");
               
            }

        }
        private void saveBasicValue(String time)
        {
            string sql = "insert into [PQ_Basic" + time + "]([RecTime],[IArms] ,[IBrms] ,[ICrms] ,[INrms] ,[UArms] ,[UBrms] ,[UCrms] ,[UNrms] ,[UZrms] ,[FA] ,[FB] ,[FC] ,[PA] ,[PB] ,[PC] ,[P] ,[QA] ,[QB] ,[QC] ,[PFA] ,[PFB] ,[PFC] ,[PF] ,[SA] ,[SB] ,[SC] ,[S] ,[PFAA] ,[PFAB] ,[PFAC] )values('" + (DateTime.Now + "." + DateTime.Now.Millisecond)/*DateTime.Now.Ticks*/
                + "'," + IArms + "," + IBrms + "," + ICrms + "," + INrms + "," + UArms + "," + UBrms + "," + UCrms + "," + UNrms + "," + UZrms + "," + FA + "," + FB + "," + FC + "," + PA + "," + PB + "," + PC + "," + P + "," + QA + "," + QB + "," + QC + "," + PFA + "," + PFB + "," + PFC + "," + PF + "," + SA + "," + SB + "," + SC + "," + S + "," + PFAA + "," + PFAB + "," + PFAC + ")";
            Console.WriteLine(sql);
            accessUtil.ExecuteNoQuery(sql);
            
           
        }

        public void basicCalc()
        {
            //计算频率
            calcFreq();

            //计算功率因数角
            calcPowerFactorAngle();

            //计算有效值
            calcRMS();
            //计算有功功率
            calcActivePower();
            //计算视在功率
            calcApparentPower();
            //计算功率因数
            calcPowerFactor();

            //计算无功功率
            calcReactivePower();

        }
        public void calcPowerFactorAngle()
        {
            PFAA = calcSinglePowerFactorAngle(data[indexUA], data[indexIA], FA);
            PFAB = calcSinglePowerFactorAngle(data[indexUB], data[indexIB], FB);
            PFAC = calcSinglePowerFactorAngle(data[indexUC], data[indexIC], FC);
        }
        public double calcSinglePowerFactorAngle(double[] u,double [] c,double f)
        {
            int index = random.Next(9) * u.Length / 10;
            int startIndex = 0, endIndex = 0;
            double startT = 0.0, endT = 0.0;
            for (int i = index; i < u.Length; i++)
            {
                if (u[i] < 0 && u[i + 1] > 0)
                {
                    startIndex = i;
                    index = i ;
                    break;
                }
            }
            for (int i = index; i < c.Length; i++)
            {
                if (c[i] < 0 && c[i + 1] > 0)
                {
                    endIndex = i;
                    break;
                }
            }
            startT = (startIndex * u[startIndex + 1] - u[startIndex] * (startIndex + 1)) / (u[startIndex + 1] - u[startIndex]);
            endT = (endIndex * c[endIndex + 1] - c[endIndex] * (endIndex + 1)) / (c[endIndex + 1] - c[endIndex]);
            return  (endT - startT)*360/(cfg.sampleFreq/f);
        }
        public void calcHarm()
        {
            calcSingleHarm(data[indexUA],harmUA);
            calcSingleHarm(data[indexUB], harmUB);
            calcSingleHarm(data[indexUC], harmUC);

            calcSingleHarm(data[indexIA],harmIA);
            calcSingleHarm(data[indexIB],harmIB);
            calcSingleHarm(data[indexIC],harmIC);
        }

        public void calcSingleHarm(double [] d,double [] hr)
        {
            int len = 1;
            while (true)
            {
                len *= 2;
                if(len >= d.Length)
                    break;
            }
            float []img = new float [len];
            float [] nd = new float[len];
            double [] amp = new double [len];
            double [] f = new double [len];
            for (int i = 0; i < d.Length; i++)
            {
                nd[i] = Convert.ToSingle(d[i]);
            }
            int mIndex = 0;
            for (int i = d.Length - 1; i > 2; i-- )
            {
                if (d[i - 1] > d[i] && d[i - 1] > d[i - 2] || d[i - 1] < d[i] && d[i - 1] < d[i - 2])
                {
                    mIndex = i - 1;
                    break;
                }
            }
            for (int i = d.Length; i < len;i ++ )
            {
               // nd[i] = 0;
                nd[i] = nd[2 * mIndex - i];
            }
            TWFFT.FFT(nd,img);
            for (int i = 0; i < d.Length; i++)
            {
                amp[i] = Math.Sqrt(nd[i] * nd[i] + img[i] * img[i]) * 2 / len;
                f[i] = cfg.sampleFreq / len * i;
            }
            for (int i = 1; i <= 50;i++ )
            {

            }
        }
        private void calcFreq()
        {
            FA = calcSingleFreq(data[indexUA]);
            FB = calcSingleFreq(data[indexUB]);
            FC = calcSingleFreq(data[indexUC]);

        }
        private double calcSingleFreq(double [] d)
        {
            int index = random.Next(9) * d.Length / 10;
            int startIndex = 0, endIndex = 0;
            double startT = 0.0, endT = 0.0;
            for (int i = index; i < d.Length; i++)
            {
                if (d[i] < 0 && d[i + 1] > 0)
                {
                    startIndex = i;
                    index = i + 2;
                    break;
                }
            }
            for (int i = index; i < d.Length; i++)
            {
                if (d[i] > 0 && d[i + 1] < 0)
                {
                    endIndex = i;
                    break;
                }
            }
            startT = (startIndex * d[startIndex+1] -d[startIndex]*(startIndex+1))/(d[startIndex+1] -d[startIndex]);
            endT = (endIndex * d[endIndex + 1] - d[endIndex] * (endIndex + 1)) / (d[endIndex + 1] - d[endIndex]);
            return cfg.sampleFreq / (endT - startT) / 2;
        }
        private void calcPowerFactor()
        {
            PFA = PA / SA;
            PFB = PB / SB;
            PFC = PC / SC;
            PF = P / S;
        }

        public void calcRMS()
        {
            //计算电压有效值
            UArms = calcSingleRMS(data[indexUA]);
            UBrms = calcSingleRMS(data[indexUB]);
            UCrms = calcSingleRMS(data[indexUC]);
            UNrms = calcSingleRMS(data[indexUN]);
            UZrms = calcSingleRMS(data[indexUZ]);

            ////计算电流有效值
            IArms = calcSingleRMS(data[indexIA]);
            IBrms = calcSingleRMS(data[indexIB]);
            ICrms = calcSingleRMS(data[indexIC]);
            INrms = calcSingleRMS(data[indexIN]);

           
        }
        public double calcSingleRMS(double [] d )
        {
            double re = 0.0; ;
            for (int i = 0; i < d.Length; i++)
            {
                re += d[i] * d[i];
            }
            re /= d.Length;
            re = Math.Sqrt(re);
            return re;
        }

        public void calcActivePower()
        {
            PA = clacSingleActivePower(data[indexUA], data[indexIA]);
            PB = clacSingleActivePower(data[indexUB], data[indexIB]);
            PC = clacSingleActivePower(data[indexUB], data[indexIC]);
            P = PA + PB + PC;
        }
        public double clacSingleActivePower(double[] u, double[] i)
        {
            double p = 0.0; ;
            for (int k = 0; k < u.Length; k++)
            {
                p += u[k] * i[k];
            }
            p /= u.Length;
            return p;
        }
        public void calcApparentPower()
        {
            SA = UArms * IArms;
            SB = UBrms * IBrms;
            SC = UCrms * ICrms;
            S = SA + SB + SC;
        }
        public void calcReactivePower()
        {
            QA = Math.Sqrt(SA * SA - PA * PA);
            QB = Math.Sqrt(SB * SB - PB * PB);
            QC = Math.Sqrt(SC * SC - PC * PC);
            
            if (double.IsNaN(QC))
            {
                QC = 0.0;
            }
            Q = QA + QB + QC;
        }
    }
}
